﻿using CanDoo.Admin.Core.Contracts;
using CanDoo.Admin.Core.Models;
using CanDoo.Core.Data;
using Mehdime.Entity;
using Microsoft.AspNet.Identity;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Claims;

namespace CanDoo.Admin.Core.Identity
{
    public class UserStore : IUserStore<User, long>,
        IUserLockoutStore<User, long>,
        IUserPasswordStore<User, long>,
        IUserTwoFactorStore<User, long>,
        IRoleStore<Role, long>,
        IUserClaimStore<User, long>,
        CanDoo.Core.Dependency.IScopeDependency
    {
        public IUserContract UserContract { get; private set; }
        public IRoleContract RoleContract { get; private set; }
        public IUserClaimContract UserClaimContract { get; private set; }
        
        public IDbContextScopeFactory DbContextScopeFactory { get; private set; }

        #region 实现 IUserStore

        public UserStore(IUserContract userManager, IRoleContract roleManager, IUserClaimContract userClaimContract,IDbContextScopeFactory dbContextScopeFactory)
        {
            RoleContract = roleManager;
            UserContract = userManager;
            UserClaimContract = userClaimContract;
            DbContextScopeFactory = dbContextScopeFactory;
        }

        public Task CreateAsync(User user)
        {
            return Task.Run(() => this.UserContract.AddEntity(user));
        }

        public Task DeleteAsync(User user)
        {
            return Task.Run(() => this.UserContract.DeleteEntity(user));
        }

        public void Dispose()
        {

        }

        public Task<User> FindByIdAsync(long userId)
        {
            using (var scop = DbContextScopeFactory.Create())
            {
                var user = this.UserContract.GetById(userId);
                if(user.Enable)
                    return Task.FromResult(user);
                return Task.FromResult((User)null);
            }
        }

        public Task<User> FindByNameAsync(string userName)
        {
            var user = this.UserContract.FindByName(userName);
            if (user != null && user.Enable)
                return Task.FromResult(user);
            return Task.FromResult((User)null);
        }

        public Task UpdateAsync(User user)
        {
            return Task.Run(() => this.UserContract.UpdateEntity(user));
        }

        #endregion

        #region IUserPasswordStore 实现

        public Task SetPasswordHashAsync(User user, string passwordHash)
        {
            user.PasswordHash = passwordHash;

            return Task.FromResult(0);
        }

        public Task<string> GetPasswordHashAsync(User user)
        {
            var result = string.Empty;
            if (user != null)
                result = user.PasswordHash;

            return Task<string>.FromResult(result);
        }

        public Task<bool> HasPasswordAsync(User user)
        {
            return Task.FromResult<bool>(!string.IsNullOrEmpty(user.PasswordHash));
        }

        #endregion

        #region Role 实现

        public Task CreateAsync(Role role)
        {
            RoleContract.AddEntity(role);
            return Task.FromResult(0);
        }

        public Task UpdateAsync(Role role)
        {
            RoleContract.UpdateEntity(role);
            return Task.FromResult(0);
        }

        public Task DeleteAsync(Role role)
        {
            RoleContract.DeleteEntity(role);
            return Task.FromResult(0);
        }

        Task<Role> IRoleStore<Role, long>.FindByIdAsync(long roleId)
        {
            return Task.FromResult(RoleContract.GetById(roleId));
        }

        Task<Role> IRoleStore<Role, long>.FindByNameAsync(string roleName)
        {
            return Task.FromResult(RoleContract.FindByName(roleName));
        }

        #endregion

        #region IUserLockoutStore 实现

        public Task<DateTimeOffset> GetLockoutEndDateAsync(User user)
        {

            return Task.FromResult(user.LockoutEndDateUtc.HasValue ?
                new DateTimeOffset(DateTime.SpecifyKind(user.LockoutEndDateUtc.Value, DateTimeKind.Utc)) : new DateTimeOffset());
        }

        public Task SetLockoutEndDateAsync(User user, DateTimeOffset lockoutEnd)
        {
            user.LockoutEndDateUtc = lockoutEnd.DateTime;
            return Task.FromResult(0);
        }

        public Task<int> IncrementAccessFailedCountAsync(User user)
        {
            user.AccessFailedCount++;
            return Task.FromResult(user.AccessFailedCount);
        }

        public Task ResetAccessFailedCountAsync(User user)
        {
            user.AccessFailedCount = 0;
            return Task.FromResult(0);
        }

        public Task<int> GetAccessFailedCountAsync(User user)
        {
            return Task.FromResult(user.AccessFailedCount);
        }

        public Task<bool> GetLockoutEnabledAsync(User user)
        {
            return Task.FromResult(user.LockoutEnabled);
        }

        public Task SetLockoutEnabledAsync(User user, bool enabled)
        {
            user.LockoutEnabled = true;
            
            return Task.FromResult(0);
        }


        #endregion

        #region IUserTwoFactorStore

        public Task SetTwoFactorEnabledAsync(User user, bool enabled)
        {
            user.TwoFactorEnabled = enabled;
            UserContract.UpdateEntity(user);
            return Task.FromResult(0);
        }

        public Task<bool> GetTwoFactorEnabledAsync(User user)
        {
            return Task.FromResult(user.TwoFactorEnabled);
        }

        #endregion

        #region IUserClaimStore<User, long>,

        public async Task<IList<Claim>> GetClaimsAsync(User user)
        {
            return await UserClaimContract.GetClaimsAsync(user.Id);
        }

        public async Task AddClaimAsync(User user, Claim claim)
        {
            await UserClaimContract.AddClaimAsync(user.Id, claim);
        }

        public async Task RemoveClaimAsync(User user, Claim claim)
        {
            await UserClaimContract.RemoveClaimAsync(user.Id, claim);
        }

        #endregion
    }
}
